package cn.iocoder.yudao.module.dify.service.translationtaskrecords;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.dify.config.DifyWorkflowManager;
import cn.iocoder.yudao.module.dify.controller.admin.translationtaskrecords.vo.TranslateWorkflowTextTaskData;
import cn.iocoder.yudao.module.dify.controller.admin.translationtaskrecords.vo.TranslationTaskRecordsPageReqVO;
import cn.iocoder.yudao.module.dify.controller.admin.translationtaskrecords.vo.TranslationTaskRecordsSaveReqVO;
import cn.iocoder.yudao.module.dify.dal.dataobject.translationtaskfile.TranslationTaskFileDO;
import cn.iocoder.yudao.module.dify.dal.dataobject.translationtaskrecords.TranslationTaskRecordsDO;
import cn.iocoder.yudao.module.dify.dal.mysql.translationtaskfile.TranslationTaskFileMapper;
import cn.iocoder.yudao.module.dify.dal.mysql.translationtaskrecords.TranslationTaskRecordsMapper;
import cn.iocoder.yudao.module.dify.util.FileContentReaderUtils;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import com.alibaba.fastjson.JSON;
import io.github.imfangs.dify.client.DifyWorkflowClient;
import io.github.imfangs.dify.client.callback.WorkflowStreamCallback;
import io.github.imfangs.dify.client.enums.FileTransferMethod;
import io.github.imfangs.dify.client.enums.FileType;
import io.github.imfangs.dify.client.enums.ResponseMode;
import io.github.imfangs.dify.client.event.*;
import io.github.imfangs.dify.client.exception.DifyApiException;
import io.github.imfangs.dify.client.model.file.FileInfo;
import io.github.imfangs.dify.client.model.file.FileUploadRequest;
import io.github.imfangs.dify.client.model.file.FileUploadResponse;
import io.github.imfangs.dify.client.model.workflow.WorkflowRunRequest;
import io.github.imfangs.dify.client.model.workflow.WorkflowRunResponse;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.dify.enums.ErrorCodeConstants.TRANSLATION_TASK_RECORDS_NOT_EXISTS;

/**
 * dify翻译工作流任务记录 Service 实现类
 *
 * @author 芋道源码
 */
@Slf4j
@Service
@Validated
public class TranslationTaskRecordsServiceImpl implements TranslationTaskRecordsService {

    @Resource
    private TranslationTaskRecordsMapper translationTaskRecordsMapper;

    @Autowired
    private DifyWorkflowManager difyWorkflowManager;

    @Resource
    private FileApi fileApi;

    @Resource
    private TranslationTaskFileMapper translationTaskFileMapper;


    @Override
    public Long createTranslationTaskRecords(TranslationTaskRecordsSaveReqVO createReqVO) {
        // 插入
        TranslationTaskRecordsDO translationTaskRecords = BeanUtils.toBean(createReqVO, TranslationTaskRecordsDO.class);
        translationTaskRecordsMapper.insert(translationTaskRecords);
        // 返回
        return translationTaskRecords.getId();
    }

    @Override
    public void updateTranslationTaskRecords(TranslationTaskRecordsSaveReqVO updateReqVO) {
        // 校验存在
        validateTranslationTaskRecordsExists(updateReqVO.getId());
        // 更新
        TranslationTaskRecordsDO updateObj = BeanUtils.toBean(updateReqVO, TranslationTaskRecordsDO.class);
        translationTaskRecordsMapper.updateById(updateObj);
    }

    @Override
    public void deleteTranslationTaskRecords(Long id) {
        // 校验存在
        validateTranslationTaskRecordsExists(id);
        // 删除
        translationTaskRecordsMapper.deleteById(id);
    }

    private void validateTranslationTaskRecordsExists(Long id) {
        if (translationTaskRecordsMapper.selectById(id) == null) {
            throw exception(TRANSLATION_TASK_RECORDS_NOT_EXISTS);
        }
    }

    @Override
    public TranslationTaskRecordsDO getTranslationTaskRecords(Long id) {
        return translationTaskRecordsMapper.selectById(id);
    }

    @Override
    public PageResult<TranslationTaskRecordsDO> getTranslationTaskRecordsPage(TranslationTaskRecordsPageReqVO pageReqVO) {
        return translationTaskRecordsMapper.selectPage(pageReqVO);
    }


    @Override
    public Long translateWorkflowUploadCreate(MultipartFile file, Long userId) throws IOException, DifyApiException {
        FileUploadRequest fileUploadRequest = FileUploadRequest.builder()
                .user(userId.toString())
                // 不传默认为application/octet-stream
                .mediaType(MediaType.parse("text/plain"))
                .build();
        DifyWorkflowClient translateWorkflowClient = difyWorkflowManager.getClient("translate2");
        FileUploadResponse uploadResponse = translateWorkflowClient.uploadFile(fileUploadRequest, file.getInputStream(), file.getOriginalFilename());
        // 创建任务数据入表
        TranslationTaskRecordsSaveReqVO translationTaskRecordsSaveReqVO = new TranslationTaskRecordsSaveReqVO();
        translationTaskRecordsSaveReqVO.setFileId(uploadResponse.getId());
        translationTaskRecordsSaveReqVO.setOriginalName(uploadResponse.getName());
        translationTaskRecordsSaveReqVO.setMimeType(uploadResponse.getMimeType());
        translationTaskRecordsSaveReqVO.setDifyFileResponse(JSON.toJSONString(uploadResponse));
        translationTaskRecordsSaveReqVO.setProcessStatus(0);// 待处理
        translationTaskRecordsSaveReqVO.setExtension(uploadResponse.getExtension());
        translationTaskRecordsSaveReqVO.setReviewStatus(1);// 未审核
        return createTranslationTaskRecords(translationTaskRecordsSaveReqVO);
    }

    @Override
    public Boolean startTranslateTaskById(Long id) throws DifyApiException, IOException, InterruptedException {
        TranslationTaskRecordsDO translationTaskRecords = translationTaskRecordsMapper.selectOne(TranslationTaskRecordsDO::getId, id);
        translationTaskRecords.setProcessStatus(1);
        DifyWorkflowClient translateWorkflowClient = difyWorkflowManager.getClient("translate2");
        // 创建文件信息
        FileInfo fileInfo = FileInfo.builder()
                .type(FileType.DOCUMENT)
                .transferMethod(FileTransferMethod.LOCAL_FILE)
                .uploadFileId(translationTaskRecords.getFileId())
                .build();

        Map<String, Object> inputs = new HashMap<>();
        // 创建工作流请求，需要在开始节点增加两个参数，例: query: 文本, file: 类型选择文件列表
//        inputs.put("translatedDocument", Collections.singletonList(fileInfo));
        inputs.put("file", fileInfo);
        WorkflowRunRequest request = WorkflowRunRequest.builder()
                .inputs(inputs)
                .responseMode(ResponseMode.STREAMING)
                .user(translationTaskRecords.getCreator())
                .build();
        // 用于等待异步回调完成
        CountDownLatch latch = new CountDownLatch(1);
        StringBuilder outputBuilder = new StringBuilder();
        // 执行工作流流式请求
        translateWorkflowClient.runWorkflowStream(request, new WorkflowStreamCallback() {
            @Override
            public void onWorkflowStarted(WorkflowStartedEvent event) {
                System.out.println("工作流开始: " + event);
            }

            @Override
            public void onNodeStarted(NodeStartedEvent event) {
                System.out.println("节点开始: " + event);
            }

            @Override
            public void onNodeFinished(NodeFinishedEvent event) {
//                System.out.println("节点完成: " + event);
                // 直接打印事件，不尝试访问可能不存在的方法
//                if (ObjectUtil.isNotEmpty(event) && ObjectUtil.isNotEmpty(event.getData()) && event.getData().getTitle().contains("结束")) {
//                    outputBuilder.append(event.getData().getOutputs().get("text").toString());
//                }
            }

            @Override
            public void onWorkflowFinished(WorkflowFinishedEvent event) {
                System.out.println("工作流完成: " + event);
                Object output = event.getData().getOutputs().get("output");
                if (ObjectUtil.isNotEmpty(output)) {
                    ArrayList output1 = (ArrayList) output;
                    // 使用 forEach 确保每个元素都被处理
                    output1.forEach(item -> outputBuilder.append(item.toString()).append("\n"));
                }
                latch.countDown();


            }

            @Override
            public void onWorkflowTextChunk(WorkflowTextChunkEvent event) {

            }

            @Override
            public void onTtsMessage(TtsMessageEvent event) {
                System.out.println("收到TTS消息: " + event);
            }

            @Override
            public void onTtsMessageEnd(TtsMessageEndEvent event) {
                System.out.println("TTS消息结束: " + event);
            }

            @Override
            public void onError(ErrorEvent event) {
                System.out.println("错误事件: " + event);
            }

            @Override
            public void onPing(PingEvent event) {
                System.out.println("心跳: " + event);
            }

            @Override
            public void onException(Throwable throwable) {
                System.out.println("异常: " + throwable.getMessage());
                latch.countDown();
            }
        });
        // 等待流式响应完成
        boolean completed = latch.await(36000, TimeUnit.SECONDS);
        if (!completed) {
            new RuntimeException("流式响应超时");
        }
        log.info("完整输出====================================>: " + outputBuilder);
        if (StrUtil.isNotEmpty(outputBuilder)) {
            byte[] content = outputBuilder.toString().getBytes(StandardCharsets.UTF_8);
            String fileName = FileNameUtil.getPrefix(translationTaskRecords.getOriginalName()) + "-en." + FileNameUtil.getSuffix(translationTaskRecords.getOriginalName());
            String fileUrl = fileApi.createFile(fileName, content);
            translationTaskRecords.setMinioUrl(fileUrl);
            translationTaskRecords.setProcessStatus(2);
        }
        translationTaskRecordsMapper.updateById(translationTaskRecords);
        return true;
    }

    @Override
    public Long translateWorkflowUploadCreateTask(MultipartFile file, Long userId) throws IOException {
        TranslationTaskRecordsSaveReqVO translationTaskRecordsSaveReqVO = new TranslationTaskRecordsSaveReqVO();
        String fileUrl = fileApi.createFile(file.getOriginalFilename(), IoUtil.readBytes(file.getInputStream()));
        translationTaskRecordsSaveReqVO.setOriginalName(file.getOriginalFilename());
        translationTaskRecordsSaveReqVO.setMimeType(file.getName());
        translationTaskRecordsSaveReqVO.setProcessStatus(0);// 待处理
        translationTaskRecordsSaveReqVO.setDifyDownloadUrl(fileUrl);
        translationTaskRecordsSaveReqVO.setReviewStatus(1);// 未审核
        return createTranslationTaskRecords(translationTaskRecordsSaveReqVO);
    }

    @Override
    public Boolean translateWorkflowSplitFileById(Long id) {
        TranslationTaskRecordsDO translationTaskRecordsDO = translationTaskRecordsMapper.selectOne(TranslationTaskRecordsDO::getId, id);
        translationTaskRecordsDO.setProcessStatus(1);
        TranslateWorkflowTextTaskData translateWorkflowTextTaskData = new TranslateWorkflowTextTaskData();
        Long totalTokens = 0L;
        try {
            translateWorkflowTextTaskData = translateWorkflowSplitFile(translationTaskRecordsDO.getDifyDownloadUrl(), translationTaskRecordsDO.getCreator());
        } catch (Exception e) {
            log.error("处理文件失败: " + e.getMessage());
            return false;
        }
        translationTaskRecordsDO.setProcessStatus(2);
        translationTaskRecordsDO.setMinioUrl(translateWorkflowTextTaskData.getEngFileUrl());
        translationTaskRecordsDO.setTotalTokens(translateWorkflowTextTaskData.getTotalTokens());
        return translationTaskRecordsMapper.updateById(translationTaskRecordsDO) > 0;
    }

    @Override
    public TranslateWorkflowTextTaskData translateWorkflowSplitFile(String fileUrl, String userId) throws IOException {
//        fileUrl = "http://47.115.137.160:9003/file/【测试】风险管理报告 v8(5).docx";
        log.info("开始处理文件: " + fileUrl);
        TranslateWorkflowTextTaskData translateWorkflowTextTaskData = new TranslateWorkflowTextTaskData();
        boolean docxFile = FileContentReaderUtils.isDocxFile(fileUrl);
        boolean pdfFile = FileContentReaderUtils.isPdfFile(fileUrl);
//        FileContentReaderUtils.readContentFromFileUrl(fileUrl);
        //读取文件docx或pdf
        if (pdfFile) {
//            try (PDDocument document = PDDocument.load(file.getInputStream())) {
//                PDFTextStripper pdfStripper = new PDFTextStripper();
//                String pdfText = pdfStripper.getText(document);
//                // 处理提取到的文本
//            } catch (IOException e) {
//                // 处理异常
//            }
        }
        if (docxFile) {
            // 编码URL中的特殊字符
            String encodedUrl = FileContentReaderUtils.encodeUrl(fileUrl);

            // 下载文件内容
            byte[] fileContent = FileContentReaderUtils.downloadFileFromUrl(encodedUrl);
            // 加载DOCX文档
            XWPFDocument document = new XWPFDocument(new ByteArrayInputStream(fileContent));
            // 翻译文档
            TranslateWorkflowTextTaskData translatedDocument = translateDocxFile(document, userId);

            // 将翻译后的文档转换为字节数组
            byte[] translatedBytes = FileContentReaderUtils.documentToByteArray(translatedDocument.getXwpfDocument());

            // 保存翻译后的文档
            String fileName = FileNameUtil.getName(fileUrl);
            if (StrUtil.isAllNotBlank(fileName) && !StrUtil.isBlankOrUndefined(fileName)) {
                fileName = FileNameUtil.getPrefix(fileName) + "-en." + FileNameUtil.getSuffix(fileName);
            } else {
                fileName = "translated_document.docx";
            }
            String enFileUrl = fileApi.createFile(fileName, translatedBytes);
            translateWorkflowTextTaskData.setEngFileUrl(enFileUrl);
            translateWorkflowTextTaskData.setTotalTokens(translatedDocument.getTotalTokens());
        }
        return translateWorkflowTextTaskData;
    }

    @Override
    public TranslateWorkflowTextTaskData translateWorkflowTextExecuteTask(String text, String userTerm, String userId) throws DifyApiException, IOException {
        Map<String, Object> inputs = new HashMap<>();
        // 创建工作流请求，需要在开始节点增加两个参数，例: query: 文本, file: 类型选择文件列表
//        inputs.put("translatedDocument", Collections.singletonList(fileInfo));
        inputs.put("userText", text);
        inputs.put("userTerm", userTerm);
        DifyWorkflowClient translateWorkflowClient = difyWorkflowManager.getClient("translate3");
        WorkflowRunRequest request = WorkflowRunRequest.builder()
                .inputs(inputs)
                .responseMode(ResponseMode.BLOCKING)
                .user(userId)
                .build();
        WorkflowRunResponse.WorkflowRunData data = translateWorkflowClient.runWorkflow(request).getData();
        Object result = data.getOutputs().get("result");
        TranslateWorkflowTextTaskData translateWorkflowTextTaskData = TranslateWorkflowTextTaskData.builder()
                .result(result.toString())
                .result(result.toString())
                .totalTokens(Long.valueOf(data.getTotalTokens()))
                .build();
        //测试用
//        TranslateWorkflowTextTaskData translateWorkflowTextTaskData = TranslateWorkflowTextTaskData.builder()
//                .result("[翻译后]"+ text)
//                .totalTokens(Long.valueOf(text.length()))
//                .build();
        return translateWorkflowTextTaskData;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long translateWorkflowCreateTask(List<String> fileUrls, Long userId) {
        // 插入任务主表
        TranslationTaskRecordsDO translationTaskRecordsDO = new TranslationTaskRecordsDO();
        translationTaskRecordsDO.setReviewStatus(1);
        translationTaskRecordsDO.setRetryCount(0);
        translationTaskRecordsDO.setTotalTokens(0L);
        int insert = translationTaskRecordsMapper.insert(translationTaskRecordsDO);
        ArrayList<TranslationTaskFileDO> translationTaskFileDOS = new ArrayList<>();
        for (String fileUrl : fileUrls) {
            TranslationTaskFileDO translationTaskFileDO = new TranslationTaskFileDO();
            translationTaskFileDO.setDifyTranslationTaskRecordsId(translationTaskRecordsDO.getId());
            translationTaskFileDO.setOriginalUrl(fileUrl);
            translationTaskFileDO.setOriginalName(FileNameUtil.getName(fileUrl));
            translationTaskFileDO.setTotalTokens(0L);
            translationTaskFileDO.setProcessStatus(0);
            translationTaskFileDO.setRetryCount(0);
            translationTaskFileDO.setReviewStatus(1);
            translationTaskFileDOS.add(translationTaskFileDO);
        }
        translationTaskFileMapper.insertBatch(translationTaskFileDOS);
        return translationTaskRecordsDO.getId();
    }

    public TranslateWorkflowTextTaskData translateDocxFile(XWPFDocument document, String userId) throws IOException {
        // 克隆原始文档以保留格式
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        document.write(bos);
        Long totalTokens = 0L;
        XWPFDocument translatedDocument = new XWPFDocument(new ByteArrayInputStream(bos.toByteArray()));
        TranslateWorkflowTextTaskData translateWorkflowTextTaskData = new TranslateWorkflowTextTaskData();
        // 1. 遍历并翻译段落
        List<XWPFParagraph> paragraphs = translatedDocument.getParagraphs();
        try {
            for (XWPFParagraph paragraph : paragraphs) {
                TranslateWorkflowTextTaskData TextTaskData = translateParagraphWithWorkflow(paragraph, userId);
                totalTokens = totalTokens + TextTaskData.getTotalTokens();
            }

            // 2. 遍历并翻译表格内容
            List<XWPFTable> tables = translatedDocument.getTables();
            for (XWPFTable table : tables) {
                TranslateWorkflowTextTaskData TextTaskData2 = translateTableWithWorkflow(table, userId);
                totalTokens = totalTokens + TextTaskData2.getTotalTokens();
            }
        } catch (Exception e) {
            log.error("翻译调用dify失败: " + e.getMessage());
            e.printStackTrace();
            new RuntimeException("翻译调用dify失败");
        }
        translateWorkflowTextTaskData.setXwpfDocument(translatedDocument);
        translateWorkflowTextTaskData.setTotalTokens(totalTokens);
        return translateWorkflowTextTaskData;
    }


    /**
     * 翻译段落内容
     *
     * @param paragraph 段落对象
     */
    private TranslateWorkflowTextTaskData translateParagraphWithWorkflow(XWPFParagraph paragraph, String userId) throws DifyApiException, IOException {
        // 获取段落中的所有文本块
        List<XWPFRun> runs = paragraph.getRuns();
        TranslateWorkflowTextTaskData translateWorkflowTextTask = new TranslateWorkflowTextTaskData();
        translateWorkflowTextTask.setTotalTokens(0L);
        if (runs != null && !runs.isEmpty()) {
            StringBuilder paragraphText = new StringBuilder();
            // 提取段落全部文本
            for (XWPFRun run : runs) {
                paragraphText.append(run.getText(0));
            }
            String originalText = paragraphText.toString();
            if (!originalText.trim().isEmpty()) {
                if (!StrUtil.isBlankOrUndefined(originalText) && FileContentReaderUtils.containsChinese(originalText)) {
                    // 这里调用翻译API进行翻译
                    TranslateWorkflowTextTaskData translateWorkflowTextTaskData = translateWorkflowTextExecuteTask(originalText, null, userId);
                    translateWorkflowTextTask.setTotalTokens(translateWorkflowTextTaskData.getTotalTokens());
                    // 清除原内容并设置翻译后的内容
                    for (int i = 0; i < runs.size(); i++) {
                        if (i == 0) {
                            runs.get(i).setText(translateWorkflowTextTaskData.getResult(), 0);
                        } else {
                            runs.get(i).setText("", 0);
                        }
                    }
                }
            }
        }
        return translateWorkflowTextTask;
    }

    /**
     * 翻译表格内容
     *
     * @param table 表格对象
     */
    private TranslateWorkflowTextTaskData translateTableWithWorkflow(XWPFTable table, String userId) throws DifyApiException, IOException {
        List<XWPFTableRow> rows = table.getRows();
        TranslateWorkflowTextTaskData translateWorkflowTextTask = new TranslateWorkflowTextTaskData();
        translateWorkflowTextTask.setTotalTokens(0L);
        for (XWPFTableRow row : rows) {
            List<XWPFTableCell> cells = row.getTableCells();
            for (XWPFTableCell cell : cells) {
                // 遍历单元格中的段落
                List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
                for (XWPFParagraph cellParagraph : cellParagraphs) {
                    TranslateWorkflowTextTaskData translateWorkflowTextTaskData = translateParagraphWithWorkflow(cellParagraph, userId);
                    translateWorkflowTextTask.setTotalTokens(translateWorkflowTextTask.getTotalTokens() + translateWorkflowTextTaskData.getTotalTokens());
                }
                // 处理单元格中的嵌套表格
                List<XWPFTable> nestedTables = cell.getTables();
                for (XWPFTable nestedTable : nestedTables) {
                    TranslateWorkflowTextTaskData nestedTableTaskData = translateTableWithWorkflow(nestedTable, userId);
                    translateWorkflowTextTask.setTotalTokens(translateWorkflowTextTask.getTotalTokens() + nestedTableTaskData.getTotalTokens());
                }
            }
        }
        return translateWorkflowTextTask;
    }
}
